package org.db;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.db.dao.BauwerkslinienDAO;
import org.db.dao.DAO;
import org.db.dao.GleisDAO;
import org.db.dao.HoehenlinienDAO;
import org.db.dao.KruemmungslinienDAO;
import org.db.dao.LageskizzenGVPDAO;
import org.db.dao.LageskizzenWeichenDAO;
import org.db.dao.ProjektDatenDAO;
import org.db.dao.Uebergangsbogen;
import org.db.dao.UeberhoehungslinienDAO;
import org.db.dao.Ueberhoehungsrampe;
import org.db.dao.change.AddProjektElement;
import org.db.dao.change.ProjektChange;
import org.db.dao.change.RemoveProjektElement;
import org.db.dao.change.UpdateProjektElement;
import org.db.dao.query.QueryResult;
import org.db.util.XMLTags;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Manager {
	
	private static Manager instance = null;
	
	private static final String dataFolder = "Data";
	private static final String SCHEMA_FILE_PATH = "resource/schema.xsd";
	
	private String loadedFilePath;
	private Document doc;
	private Element projektNode;
	private Element lageskizzenNode;
	private Element bauwerkslinienNode;
	private Element gleisNode;
	
	private ProjektDatenDAO projekt;
	private List<GleisDAO> gleisElemente;
	private SortedSet<BauwerkslinienDAO> bauwerkslinienElemente;
	private SortedSet<LageskizzenGVPDAO> lageskizzenGVPs;
	private SortedSet<LageskizzenWeichenDAO> lageskizzenWeichen;
	
	private List<ProjektChange> scheduledChanges;
	
	private GleisDAO currentGleis;
	
	private Manager(){
		reset();
	}
	
	public synchronized static Manager getInstance(){
		if(instance == null){
			instance = new Manager();
		}
		return instance;
	}
	
	private void write2Disk(){
		try {
			TransformerFactory tFactory =
			    TransformerFactory.newInstance();
			  Transformer transformer = tFactory.newTransformer();
			  transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // pretty print
		        transformer.setOutputProperty(
		            "{http://xml.apache.org/xslt}indent-amount", "4");
			  DOMSource source = new DOMSource(buildDocument());
			  StreamResult result = new StreamResult(new BufferedOutputStream(new FileOutputStream(createFilePath())));
			  transformer.transform(source, result);
//			  result = new StreamResult(System.out);
//			  transformer.transform(source, result);
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}
	
	private String createFilePath(){
		return dataFolder + File.separator + projekt.getAuftragsNr() + ".xml";
	}
	
	public QueryResult query(double position){
		BauwerkslinienDAO nearestBauwerkslinienElement = getNearestBauwerkslinienElement(position);
		HoehenlinienDAO nearestHoehenlinienElement = getNearestHoehenlinienElement(position);
		KruemmungslinienDAO nearestKruemmungslinienElement = getNearestKruemmungslinienElement(position);
		UeberhoehungslinienDAO nearestUeberhoehungslinienElement = getNearestUeberhoehungslinienElement(position);
		UeberhoehungslinienDAO nextUeberhoehungslinienElement = getNextUeberhoehungslinienElement(nearestUeberhoehungslinienElement);
		UeberhoehungslinienDAO prevUeberhoehungslinienElement = getPreviousUeberhoehungslinienElement(nearestUeberhoehungslinienElement);
		LageskizzenWeichenDAO nearestWeiche = getNearestWeiche(position);
		List<LageskizzenGVPDAO> nearestGVPs = getNearestGVPs(position);
		
		QueryResult result = new QueryResult(position, nearestBauwerkslinienElement, nearestHoehenlinienElement, nearestKruemmungslinienElement, 
				nearestUeberhoehungslinienElement, nextUeberhoehungslinienElement, 
				prevUeberhoehungslinienElement, nearestWeiche, nearestGVPs);
		saveQueryResult(result);
		
		return result;
	}
	
	public void saveQueryResult(QueryResult result) {
		StringBuilder sb = new StringBuilder();
		sb.append("Projektname: ").append(projekt.getAuftragsNr()).append("\n");
		sb.append("Stationierung: ").append(result.gets0()).append("\n");
		sb.append("Gleis: ").append(getCurrentGleis().getBezeichnung()).append("\n");
		
		sb.append(result.toString());
		
		Writer output = null;
		try {
			String path = new File(loadedFilePath).getParent();
			String filename = projekt.getAuftragsNr() + "_" + result.gets0() + ".txt";
			output = new BufferedWriter(new FileWriter(path + File.separator + filename));
			output.write(sb.toString());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (output != null) {
					output.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private UeberhoehungslinienDAO getPreviousUeberhoehungslinienElement(UeberhoehungslinienDAO ueberhoehungsElement){
		UeberhoehungslinienDAO prevUeberhoehungsElement = null;
		 
		 if(ueberhoehungsElement != null){
			 //Element davor holen, falls vorhanden
			 SortedSet<UeberhoehungslinienDAO> previousElements = Manager.getInstance().getUeberhoehungslinienElemente().headSet(ueberhoehungsElement);
			 if(!previousElements.isEmpty()){
				 prevUeberhoehungsElement = previousElements.last();
			 }
		 }
		 return prevUeberhoehungsElement;
	}
	
	private UeberhoehungslinienDAO getNextUeberhoehungslinienElement(UeberhoehungslinienDAO ueberhoehungsElement){
		 UeberhoehungslinienDAO nextUeberhoehungsElement = null;
		 
		 if(ueberhoehungsElement != null){
			 //Element danach holen, falls vorhanden
			 SortedSet<UeberhoehungslinienDAO> nextElements = Manager.getInstance().getUeberhoehungslinienElemente().tailSet(ueberhoehungsElement);		 
			 if(!nextElements.isEmpty()){
				 Iterator<UeberhoehungslinienDAO> it = nextElements.iterator();
					it.next();//das erste Element überspringen, weil es das ist, womit die Menge geteilt wurde
				 nextUeberhoehungsElement = it.next();
			 }
		 }
		
		 return nextUeberhoehungsElement;
	}
	
	/**
	 * Gibt entweder das sich auf dem Punkt befindende Bauwerk zurück, oder falls
	 * nicht vorhanden das am nächsten liegende Bauwerkselement.
	 * @param position
	 * @return
	 */
	public BauwerkslinienDAO getNearestBauwerkslinienElement(double position){
		BauwerkslinienDAO nearestBauwerkslinienElement = null;
		double minAbstand = Double.MAX_VALUE;
		for(BauwerkslinienDAO dao : bauwerkslinienElemente){
			double stationierung = dao.getStationierungVonInMeter();
			double endstationierung = dao.getStationierungBisInMeter();
			if((stationierung <= position) && (endstationierung >= position)){
				return dao;
			} else {
				double abstand = Math.min(Math.abs(position - stationierung), Math.abs(position - endstationierung));
				if(abstand <= minAbstand){
					minAbstand = abstand;
					nearestBauwerkslinienElement = dao;
				}
			}
		}
		return nearestBauwerkslinienElement;
	}
	/**
	 * Gibt das Krümmungslinienelement zurück, indem sich s0 befindet
	 * @param position
	 * @return
	 */
	public KruemmungslinienDAO getNearestKruemmungslinienElement (double position) {
		KruemmungslinienDAO nearestKruemmungslinienElement = null;
		for (KruemmungslinienDAO dao : currentGleis.getKruemmungslinienElemente()) {
			double stationierung = dao.getStationierungInMeter();
			double endstationierung = dao.getEndstationierungInMeter();
			if((stationierung <= position) && (endstationierung >= position)){
				return dao;
			} 
		}
		return nearestKruemmungslinienElement;
	}
	/**
	 * Gibt das Überhohungslinienelement zurück, indem sich s0 befindet
	 * @param position
	 * @return
	 */
	public UeberhoehungslinienDAO getNearestUeberhoehungslinienElement (double position) {
		UeberhoehungslinienDAO nearestUeberhoehungslinienElement = null;
		
		for (UeberhoehungslinienDAO dao : currentGleis.getUeberhoehungslinienElemente()) {
			double stationierung = dao.getStationierungInMeterUe();
			double endstationierung = dao.getEndstationierungInMeterUE();
			if((stationierung <= position) && (endstationierung >= position)){
				return dao;
			} 
		}
//		nearestUeberhoehungslinienElement = UeberhoehungslinienDAO.get(i);
		return nearestUeberhoehungslinienElement;
	}
	
	
	/**
	 * Gibt entweder die sich auf dem Punkt befindende Weiche zurück, oder falls
	 * nicht vorhanden die am nächsten liegende Weiche.
	 * @param position
	 * @return
	 */
	public LageskizzenWeichenDAO getNearestWeiche(double position) {
		LageskizzenWeichenDAO nearestWeiche = null;
		double minAbstand = Double.MAX_VALUE;
		for (LageskizzenWeichenDAO dao : lageskizzenWeichen) {
			double stationierung = dao.getstationWeiche();
			if (stationierung == position) {
				return dao;
			} else {
				double abstand = Math.abs(position - stationierung);
				if(abstand <= minAbstand) {
					minAbstand = abstand;
					nearestWeiche = dao;
				}
			}
		}
		return nearestWeiche;
	}
	/**
	 * Gibt entweder den sich auf dem Punkt befindende NW zurück, oder falls
	 * nicht vorhanden den am nächsten liegende NW.
	 * @param position
	 * @return
	 */
	public HoehenlinienDAO getNearestHoehenlinienElement(double position) {
		HoehenlinienDAO nearestHoehenlinienElement = null;
		double minAbstand = Double.MAX_VALUE;
		for (HoehenlinienDAO dao : getHoehenlinienElemente()) {
			double stationierung = dao.getStationierungInMeter();
			double abstand = Math.abs(position - stationierung);
			if (abstand <= minAbstand) {
				minAbstand = abstand;
				nearestHoehenlinienElement = dao;
			}

		}
		return nearestHoehenlinienElement;
	}
	
	public List<LageskizzenGVPDAO> getNearestGVPs(double position) {
		List<LageskizzenGVPDAO> nearestGVPs = new ArrayList<LageskizzenGVPDAO>();
		LageskizzenGVPDAO nearestGVP = null;
		
		for (LageskizzenGVPDAO dao : getLageskizzenGVPs()) {
			if(dao.getstationGVPLinks() == position || dao.getstationGVPRechts() == position){
				nearestGVP = dao;
				break;
			}
		}
		if(nearestGVP != null){
			nearestGVPs.add(nearestGVP);
			SortedSet<LageskizzenGVPDAO> nextGVPs = lageskizzenGVPs.tailSet(nearestGVP);
			if(!nextGVPs.isEmpty()){
				if(nextGVPs.size() > 1){//nur falls mehr als 1 Element enthalten ist, sonst ist es eh das gleiche
					Iterator<LageskizzenGVPDAO> it = nextGVPs.iterator();
					it.next();//das erste Element überspringen, weil es das ist, womit die Menge geteilt wurde
					nearestGVPs.add(it.next());
				}
			}
		} else {
			LageskizzenGVPDAO dummyGVP = new LageskizzenGVPDAO(null, position, 0, 0, null, position, 0, 0, 0, 0);
			SortedSet<LageskizzenGVPDAO> prevGVPs = lageskizzenGVPs.headSet(dummyGVP);
			if(!prevGVPs.isEmpty()){
				nearestGVPs.add(prevGVPs.last());
			}
			SortedSet<LageskizzenGVPDAO> nextGVPs = lageskizzenGVPs.tailSet(dummyGVP);
			if(!nextGVPs.isEmpty()){
				nearestGVPs.add(nextGVPs.first());
			}
		}
		return nearestGVPs;
	}
	
	public void loadXMLFile(String path){
		this.loadedFilePath = path;
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			
			//XML Dokument laden
			InputStream is = new BufferedInputStream(new FileInputStream(path));
			doc = builder.parse(is);
			System.out.println(isValidDocument(doc));
			loadProjekt();
			
			
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void loadExistingProjekt(String auftragsnummer){
		loadXMLFile(dataFolder + File.separator + auftragsnummer + ".xml");
	}
	
	/**
	 * Testet ob bereits Projekt mit gegebener Auftragsnummer existiert
	 * @param auftragsnummer die Auftragsnummer des Projektes
	 * @return TRUE wenn Projekt bereits existiert, sonst FALSE
	 */
	public boolean projektExists(String auftragsnummer){
		return new File(dataFolder + File.separator + auftragsnummer + ".xml").exists();
	}
	
	/**
	 * Testet ob bereits Projekt mit gegebener Auftragsnummer bereits geladen wurde
	 * @param auftragsnummer die Auftragsnummer des Projektes
	 * @return TRUE wenn Projekt bereits geladen, sonst FALSE
	 */
	public boolean projektLoaded(String auftragsnummer){
		return projekt != null && projekt.getAuftragsNr().equals(auftragsnummer);
	}
	
	private void loadProjekt(){
		//Wurzelknoten laden
		projektNode = doc.getDocumentElement();
			
		String auftragsnummer = ((Element)projektNode.getElementsByTagName(XMLTags.AUFTRAGSNUMMER).item(0)).getTextContent();
		String projektBeschreibung = ((Element)projektNode.getElementsByTagName(XMLTags.PROJEKTBESCHREIBUNG).item(0)).getTextContent();
		int gleisAnzahl = Integer.valueOf(((Element)projektNode.getElementsByTagName(XMLTags.GLEISANZAHL).item(0)).getTextContent());
		int geschwindigkeit = Integer.valueOf(((Element)projektNode.getElementsByTagName(XMLTags.ENTWURFSGESCHWINDIGKEIT).item(0)).getTextContent());
		String koordinatensystem = "";
		if(projektNode.getElementsByTagName(XMLTags.KOORDINATENSYSTEM).getLength() == 1){
			koordinatensystem = projektNode.getElementsByTagName(XMLTags.KOORDINATENSYSTEM).item(0).getTextContent();
		}
		String hoehensystem = "";
		if(projektNode.getElementsByTagName(XMLTags.HOEHENSSYSTEM).getLength() == 1){
			hoehensystem = projektNode.getElementsByTagName(XMLTags.HOEHENSSYSTEM).item(0).getTextContent();
		}
		projekt = new ProjektDatenDAO(auftragsnummer, projektBeschreibung, gleisAnzahl, geschwindigkeit, koordinatensystem, hoehensystem);
		
		reset();
		//Gleise laden
		loadGleise();
		//Bauwerkslinie laden
		loadBauwerkslinie();
		//Lageskizze laden
		loadLageskizze();
	}
	
	private boolean isValidDocument(Document document){
		try {
			// create a SchemaFactory capable of understanding WXS schemas
			SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

			// load a WXS schema, represented by a Schema instance
			Source schemaFile = new StreamSource(new File(SCHEMA_FILE_PATH));
			Schema schema = factory.newSchema(schemaFile);

			// create a Validator instance, which can be used to validate an instance document
			Validator validator = schema.newValidator();

			// validate the DOM tree
			validator.validate(new DOMSource(document));
		} catch (SAXException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	    return true;
	}
	
	private void reset(){
		scheduledChanges = new ArrayList<ProjektChange>();
		
		bauwerkslinienElemente = new TreeSet<BauwerkslinienDAO>();
		lageskizzenGVPs = new TreeSet<LageskizzenGVPDAO>();
		lageskizzenWeichen = new TreeSet<LageskizzenWeichenDAO>();
		gleisElemente = new ArrayList<GleisDAO>();
		
	}
	
	
	
	/**
	 * Änderung in eine Art Warteschlange übernehmen, welche erst in die XML-Datei übernommen werden wenn applyChanges() aufgerufen wird.
	 **/
	public void addProjektChange(ProjektChange change){
		scheduledChanges.add(change);
	}
	
	/**
	 * Änderung in eine Art Warteschlange übernehmen, welche erst in die XML-Datei übernommen werden wenn applyChanges() aufgerufen wird.
	 **/
	public void addProjektChanges(List<ProjektChange> changes){
		scheduledChanges.addAll(changes);
	}
	
	
	/**
	 * Ausstehende Änderungen in XML-Datei übernehmen.
	 */
	public void applyChanges(){
		for(ProjektChange change : scheduledChanges){
			if(change instanceof AddProjektElement){
				DAO element2Add = ((AddProjektElement) change).getElement2Add();
				Collection<DAO> collection = (Collection<DAO>) getCollectionForElementType(element2Add);
				collection.add(element2Add);
			} else if(change instanceof RemoveProjektElement){
				DAO element2Remove = ((RemoveProjektElement) change).getElement2Remove();
				Collection<DAO> collection = (Collection<DAO>)getCollectionForElementType(element2Remove);
				collection.remove(element2Remove);
			} else if(change instanceof UpdateProjektElement){
				DAO element2Remove = ((UpdateProjektElement) change).getElement2Remove();
				Collection<DAO> collection2 = (Collection<DAO>) getCollectionForElementType(element2Remove);
				collection2.remove(element2Remove);
				
				DAO element2Add = ((UpdateProjektElement) change).getElement2Add();
				Collection<DAO> collection1 = (Collection<DAO>) getCollectionForElementType(element2Add);
				collection1.add(element2Add);
				
			}
		}
		scheduledChanges.clear();
		write2Disk();
	}
	
	/**
	 * Gibt die passende Collection for DAO zurück.
	 * @param dao
	 * @return
	 */
	private Collection<? extends DAO> getCollectionForElementType(DAO dao){
		if(dao instanceof BauwerkslinienDAO){
			return bauwerkslinienElemente;
		} else if(dao instanceof HoehenlinienDAO){
			return currentGleis.getHoehenlinienElemente();
		} else if(dao instanceof UeberhoehungslinienDAO){
			return currentGleis.getUeberhoehungslinienElemente();
		} else if(dao instanceof KruemmungslinienDAO){
			return currentGleis.getKruemmungslinienElemente();
		} else if(dao instanceof LageskizzenGVPDAO){
			return lageskizzenGVPs;
		} else if(dao instanceof LageskizzenWeichenDAO){
			return lageskizzenWeichen;
		} else if (dao instanceof GleisDAO) {
			return gleisElemente;
		}
		return null;
	}
	
	/**
	 * Ausstehende Änderungen verwerfen.
	 */
	public void cancel(){
		scheduledChanges.clear();
	}
	
	public void executeQuery(int stationierung){
		try {
			XPath xPath = XPathFactory.newInstance().newXPath();
			String expressionString = "//Stationierung/text()";
			XPathExpression expression = xPath.compile(expressionString);
			NodeList nodeList = (NodeList)expression.evaluate(doc, XPathConstants.NODESET);
			printNodes(nodeList);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
	}
	
	private KruemmungslinienDAO getKruemmungslinienElementFromNode(Element node){
		String element = node.getElementsByTagName(XMLTags.ELEMENT).item(0).getTextContent();
		double stationierungInMeter = Double.valueOf(node.getElementsByTagName(XMLTags.STATIONIERUNG).item(0).getTextContent());
		double endstationierungInMeter = Double.valueOf(node.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).item(0).getTextContent());		
		double radius = 0;
		if (node.getElementsByTagName(XMLTags.RADIUS).getLength() == 1){
			radius = Double.valueOf(node.getElementsByTagName(XMLTags.RADIUS).item(0).getTextContent());
		}
		
		int ueberhoehung = 0;
		if (node.getElementsByTagName(XMLTags.UEBERHOEHUNG).getLength() == 1){
			ueberhoehung = Integer.valueOf(node.getElementsByTagName(XMLTags.UEBERHOEHUNG).item(0).getTextContent());
		}
		
		Uebergangsbogen uebergangsbogen = Uebergangsbogen.NONE;
		if (node.getElementsByTagName(XMLTags.UEBERGANGSBOGEN_ID).getLength() == 1) {
			uebergangsbogen = Uebergangsbogen.valueOf(node.getElementsByTagName(XMLTags.UEBERGANGSBOGEN_ID).item(0).getTextContent());
		}
		
		double laengeUeBogen = 0;
		if (node.getElementsByTagName(XMLTags.LAENGEUEBOEGN).getLength() == 1) {
			laengeUeBogen = Double.valueOf(node.getElementsByTagName(XMLTags.LAENGEUEBOEGN).item(0).getTextContent());
		}		
		
		double rp = 0;
		if (node.getElementsByTagName(XMLTags.RP).getLength() == 1) {
			rp = Double.valueOf(node.getElementsByTagName(XMLTags.RP).item(0).getTextContent());
		}
		
		KruemmungslinienDAO dao = new KruemmungslinienDAO(element, stationierungInMeter, radius, ueberhoehung, endstationierungInMeter, rp, uebergangsbogen,
				 laengeUeBogen);
		return dao;
	}
	
	private SortedSet<KruemmungslinienDAO> loadKruemmungslinienElemente(Element kruemmungslinienNode){
		SortedSet<KruemmungslinienDAO> kruemmungslinienElemente = new TreeSet<KruemmungslinienDAO>();
		
		NodeList kruemmungslinienNodes = kruemmungslinienNode.getElementsByTagName(XMLTags.KRUEMMUNGSLINIEN_ELEMENT);
		KruemmungslinienDAO dao;
		for(int i = 0; i < kruemmungslinienNodes.getLength(); i++){
			dao = getKruemmungslinienElementFromNode((Element) kruemmungslinienNodes.item(i));
			kruemmungslinienElemente.add(dao);
		}
		return kruemmungslinienElemente;
	}
	
	
	private Element createKruemmungslinienElementNode(KruemmungslinienDAO dao){
		//Knoten für ein KruemmungslinenElement anlegen
		Element kruemmungsLinie = doc.createElement(XMLTags.KRUEMMUNGSLINIEN_ELEMENT);
		
		//Knoten für Element anlegen
		Element element = doc.createElement(XMLTags.ELEMENT);
		element.appendChild(doc.createTextNode(String.valueOf(dao.getElement())));
		kruemmungsLinie.appendChild(element);
		//Knoten für Stationierung anlegen
		Element stationierung = doc.createElement(XMLTags.STATIONIERUNG);
		stationierung.appendChild(doc.createTextNode(String.valueOf(dao.getStationierungInMeter())));
		kruemmungsLinie.appendChild(stationierung);
		//Knoten für Endstationierung anlegen
		Element endstationierung = doc.createElement(XMLTags.ENDSTATIONIERUNG);
		endstationierung.appendChild(doc.createTextNode(String.valueOf(dao.getEndstationierungInMeter())));
		kruemmungsLinie.appendChild(endstationierung);
		//Knoten für Radius anlegen
		if (dao.getRadius() != 0){
			Element radius = doc.createElement(XMLTags.RADIUS);
			radius.appendChild(doc.createTextNode(String.valueOf(dao.getRadius())));
			kruemmungsLinie.appendChild(radius);
		}	
		//Knoten für Überhöhung anlegen
		if (dao.getUeberhoehung() != 0){
			Element ueberhoehung = doc.createElement(XMLTags.UEBERHOEHUNG);
			ueberhoehung.appendChild(doc.createTextNode(String.valueOf(dao.getUeberhoehung())));
			kruemmungsLinie.appendChild(ueberhoehung);
		}	
		//Knoten für Übergangsbogen-ID anlegen
		if (dao.getUebergangsbogen() != Uebergangsbogen.NONE) {
			Element uebergangsbogen = doc.createElement(XMLTags.UEBERGANGSBOGEN_ID);
			uebergangsbogen.appendChild(doc.createTextNode(String.valueOf(dao.getUebergangsbogen())));
			kruemmungsLinie.appendChild(uebergangsbogen);	
		}			
		//Knoten für LaengeUeBogen anlegen
		if (dao.getLaengeUeBogen() != 0) {
			Element laengeUeBogen = doc.createElement(XMLTags.LAENGEUEBOEGN);
			laengeUeBogen.appendChild(doc.createTextNode(String.valueOf(dao.getLaengeUeBogen())));
			kruemmungsLinie.appendChild(laengeUeBogen);
		}		
		//Knoten für RP anlegen
		if (dao.getRp() != 0) {
			Element rp = doc.createElement(XMLTags.RP);
			rp.appendChild(doc.createTextNode(String.valueOf(dao.getRp())));
			kruemmungsLinie.appendChild(rp);
		}
		
		return kruemmungsLinie;
	}
	
	public SortedSet<KruemmungslinienDAO> getKruemmungslinienElemente(){
		return currentGleis.getKruemmungslinienElemente();
	}
	
	private UeberhoehungslinienDAO getUeberhoehungslinienElementFromNode(Element node){
		double stationierungInMeterUE = Double.valueOf(node.getElementsByTagName(XMLTags.STATIONIERUNG).item(0).getTextContent());
		double endstationierungInMeterUE = Double.valueOf(node.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).item(0).getTextContent());
		
		int ueberhoehungInMM = 0;
		if (node.getElementsByTagName(XMLTags.UEBERHOEHUNG).getLength() == 1) {
			ueberhoehungInMM = Integer.valueOf(node.getElementsByTagName(XMLTags.UEBERHOEHUNG).item(0).getTextContent());
		}	
		
		double laengeRampe = 0;
		if (node.getElementsByTagName(XMLTags.LAENGERAMPE).getLength() == 1){
			laengeRampe = Double.valueOf(node.getElementsByTagName(XMLTags.LAENGERAMPE).item(0).getTextContent());
		}			
		
		Ueberhoehungsrampe ueberhoehungsrampe = Ueberhoehungsrampe.NONE;
		if (node.getElementsByTagName(XMLTags.RAMPEN_ID).getLength() == 1) {
			ueberhoehungsrampe = Ueberhoehungsrampe.valueOf(node.getElementsByTagName(XMLTags.RAMPEN_ID).item(0).getTextContent());
		}
		
		UeberhoehungslinienDAO dao = new UeberhoehungslinienDAO(stationierungInMeterUE, ueberhoehungInMM, endstationierungInMeterUE, ueberhoehungsrampe,
				 laengeRampe);
		return dao;
	}
	
	private SortedSet<UeberhoehungslinienDAO> loadUeberhoehungslinienElemente(Element ueberhoehungslinienNode){
		SortedSet<UeberhoehungslinienDAO> ueberhoehungslinienElemente = new TreeSet<UeberhoehungslinienDAO>();
		
		NodeList ueberhoehungslinienNodes = ueberhoehungslinienNode.getElementsByTagName(XMLTags.UEBERHOEHUNGSLINIEN_ELEMENT);
		UeberhoehungslinienDAO dao;
		for(int i = 0; i < ueberhoehungslinienNodes.getLength(); i++){
			dao = getUeberhoehungslinienElementFromNode((Element) ueberhoehungslinienNodes.item(i));
			ueberhoehungslinienElemente.add(dao);
		}
		
		return ueberhoehungslinienElemente;
	}
	
	
	private Element createUeberhoehunglinienElementNode(UeberhoehungslinienDAO dao){
		//Knoten für ein ÜberhöhungslinienElement anlegen
		Element ueberhoehungslinie = doc.createElement(XMLTags.UEBERHOEHUNGSLINIEN_ELEMENT);
		
		//Knoten für Stationierung anlegen
		Element stationierungUE = doc.createElement(XMLTags.STATIONIERUNG);
		stationierungUE.appendChild(doc.createTextNode(String.valueOf(dao.getStationierungInMeterUe())));
		ueberhoehungslinie.appendChild(stationierungUE);
		//Knoten für Endstationierung anlegen
		Element endstationierungInMeterUE = doc.createElement(XMLTags.ENDSTATIONIERUNG);
		endstationierungInMeterUE.appendChild(doc.createTextNode(String.valueOf(dao.getEndstationierungInMeterUE())));
		ueberhoehungslinie.appendChild(endstationierungInMeterUE);
		//Knoten für Überhöhung anlegen
		if (dao.getUeberhoehungInMM() != 0) {
			Element ueberhoehung = doc.createElement(XMLTags.UEBERHOEHUNG);
			ueberhoehung.appendChild(doc.createTextNode(String.valueOf(dao.getUeberhoehungInMM())));
			ueberhoehungslinie.appendChild(ueberhoehung);
		}	
		//Knoten für Überhöhungsrampe anlegen
		if (dao.getUeberhoehungsrampe() != Ueberhoehungsrampe.NONE){
			Element ueberhoehungsrampe = doc.createElement(XMLTags.RAMPEN_ID);
			ueberhoehungsrampe.appendChild(doc.createTextNode(String.valueOf(dao.getUeberhoehungsrampe())));
			ueberhoehungslinie.appendChild(ueberhoehungsrampe);	
		}			
		//Knoten für Rampenlänge anlegen
		if (dao.getLaengeRampe() != 0) {
			Element rampenlaenge = doc.createElement(XMLTags.LAENGERAMPE);
			rampenlaenge.appendChild(doc.createTextNode(String.valueOf(dao.getLaengeRampe())));
			ueberhoehungslinie.appendChild(rampenlaenge);
		}
		
		return ueberhoehungslinie;
	}
	
	public SortedSet<UeberhoehungslinienDAO> getUeberhoehungslinienElemente() {
		return currentGleis.getUeberhoehungslinienElemente();
	}
	
	private HoehenlinienDAO getHoehenlinienElementFromNode(Element node){
		double neigungAn = Double.valueOf(node.getElementsByTagName(XMLTags.ANKOMMENDE_NEIGUNG).item(0).getTextContent());
		double laengeAn = Double.valueOf(node.getElementsByTagName(XMLTags.ANKOMMENDE_LAENGE).item(0).getTextContent());
		double hoehe = Double.valueOf(node.getElementsByTagName(XMLTags.HOEHE).item(0).getTextContent());
		double stationierungInMeter = Double.valueOf(node.getElementsByTagName(XMLTags.STATIONIERUNG).item(0).getTextContent());
		int ra = 0;
		if(node.getElementsByTagName(XMLTags.RA).getLength() == 1){
			ra = Integer.valueOf(node.getElementsByTagName(XMLTags.RA).item(0).getTextContent());
		}
		double lt = 0;
		if(node.getElementsByTagName(XMLTags.LT).getLength() == 1){
			lt = Double.valueOf(node.getElementsByTagName(XMLTags.LT).item(0).getTextContent());
		}
		double a = 0;
		if(node.getElementsByTagName(XMLTags.A).getLength() == 1){
			a = Double.valueOf(node.getElementsByTagName(XMLTags.A).item(0).getTextContent());
		}
		double neigungAb = Double.valueOf(node.getElementsByTagName(XMLTags.ABGEHENDE_NEIGUNG).item(0).getTextContent());
		double laengeAb = Double.valueOf(node.getElementsByTagName(XMLTags.ABGEHENDE_LAENGE).item(0).getTextContent());
		
		HoehenlinienDAO dao = new HoehenlinienDAO(neigungAn, laengeAn, hoehe, stationierungInMeter,  
				 ra, lt, a, neigungAb, laengeAb);
		
		return dao;
	}
	
	private SortedSet<HoehenlinienDAO> loadHoehenlinienElemente(Element hoehenlinienNode){
		SortedSet<HoehenlinienDAO> hoehenlinienElemente = new TreeSet<HoehenlinienDAO>();
		
		NodeList hoehenlinienNodes = hoehenlinienNode.getElementsByTagName(XMLTags.HOEHENLINIEN_ELEMENT);
		HoehenlinienDAO dao;
		for(int i = 0; i < hoehenlinienNodes.getLength(); i++){
			dao = getHoehenlinienElementFromNode((Element) hoehenlinienNodes.item(i));
			hoehenlinienElemente.add(dao);
		}
		return hoehenlinienElemente;
	}
	
	private Element createHoehenlinienElementNode(HoehenlinienDAO dao){
		//Knoten für ein HöhenlinienElement anlegen
		Element hoehenlinie = doc.createElement(XMLTags.HOEHENLINIEN_ELEMENT);
		
		//Knoten für ankommende Neigung anlegen
		Element neigungAn = doc.createElement(XMLTags.ANKOMMENDE_NEIGUNG);
		neigungAn.appendChild(doc.createTextNode(String.valueOf(dao.getNeigungAn())));
		hoehenlinie.appendChild(neigungAn);
		//Knoten für ankommende Länge anlegen
		Element laengeAn = doc.createElement(XMLTags.ANKOMMENDE_LAENGE);
		laengeAn.appendChild(doc.createTextNode(String.valueOf(dao.getLaengeAn())));
		hoehenlinie.appendChild(laengeAn);
		//Knoten für Stationierung anlegen
		Element stationierung = doc.createElement(XMLTags.STATIONIERUNG);
		stationierung.appendChild(doc.createTextNode(String.valueOf(dao.getStationierungInMeter())));
		hoehenlinie.appendChild(stationierung);
		//Knoten für Höhe anlegen
		Element hoehe = doc.createElement(XMLTags.HOEHE);
		hoehe.appendChild(doc.createTextNode(String.valueOf(dao.gethoehe())));
		hoehenlinie.appendChild(hoehe);
		//Knoten für Ra anlegen
		if (dao.getRa() != 0) {
			Element ra = doc.createElement(XMLTags.RA);
			ra.appendChild(doc.createTextNode(String.valueOf(dao.getRa())));
			hoehenlinie.appendChild(ra);
		}		
		//Knoten für Lt anlegen
		if (dao.getLt() != 0) {
			Element lt = doc.createElement(XMLTags.LT);
			lt.appendChild(doc.createTextNode(String.valueOf(dao.getLt())));
			hoehenlinie.appendChild(lt);
		}
		//Knoten für A anlegen
		if (dao.getA() != 0) {
			Element a = doc.createElement(XMLTags.A);
			a.appendChild(doc.createTextNode(String.valueOf(dao.getA())));
			hoehenlinie.appendChild(a);
		}
		//Knoten für abgehende Neigung anlegen
		Element neigungAb = doc.createElement(XMLTags.ABGEHENDE_NEIGUNG);
		neigungAb.appendChild(doc.createTextNode(String.valueOf(dao.getNeigungAb())));
		hoehenlinie.appendChild(neigungAb);		
		//Knoten für abgehende Länge anlegen
		Element laengeAb = doc.createElement(XMLTags.ABGEHENDE_LAENGE);
		laengeAb.appendChild(doc.createTextNode(String.valueOf(dao.getLaengeAb())));
		hoehenlinie.appendChild(laengeAb);
		
		return hoehenlinie;
	}
	
	public SortedSet<HoehenlinienDAO> getHoehenlinienElemente() {
		return currentGleis.getHoehenlinienElemente();
	}

	private LageskizzenGVPDAO getLageskizzenGVPFromNode(Element node){
		String punktNrGVPLinks = "";
		if (node.getElementsByTagName(XMLTags.PUNKTNUMMERGVPLINKS).getLength() ==1) {			
			punktNrGVPLinks = node.getElementsByTagName(XMLTags.PUNKTNUMMERGVPLINKS).item(0).getTextContent();
		}
		String punktNrGVPRechts = "";
		if (node.getElementsByTagName(XMLTags.PUNKTNUMMERGVPRECHTS).getLength() ==1) {			
			punktNrGVPRechts = node.getElementsByTagName(XMLTags.PUNKTNUMMERGVPRECHTS).item(0).getTextContent();
		}
		double stationGVPLinks = 0;
		if (node.getElementsByTagName(XMLTags.STATIONLINKS).getLength() ==1) {			
			stationGVPLinks = Double.valueOf(node.getElementsByTagName(XMLTags.STATIONLINKS).item(0).getTextContent());
		}
		double stationGVPRechts = 0;
		if (node.getElementsByTagName(XMLTags.STATIONRECHTS).getLength() ==1) {			
			stationGVPRechts = Double.valueOf(node.getElementsByTagName(XMLTags.STATIONRECHTS).item(0).getTextContent());
		}
		int hoehenmaßGVPLinks = 0;
		if (node.getElementsByTagName(XMLTags.HOEHENMASSLINKS).getLength() ==1) {
			hoehenmaßGVPLinks = Integer.valueOf(node.getElementsByTagName(XMLTags.HOEHENMASSLINKS).item(0).getTextContent());
		}		 
		int hoehenmaßGVPRechts = 0;
		if (node.getElementsByTagName(XMLTags.HOEHENMASSRECHTS).getLength() ==1) {
			hoehenmaßGVPRechts = Integer.valueOf(node.getElementsByTagName(XMLTags.HOEHENMASSRECHTS).item(0).getTextContent());
		}
		double querGVPLinks = 0;
		if (node.getElementsByTagName(XMLTags.QUERGVPLINKS).getLength() ==1) {			
			querGVPLinks = Double.valueOf(node.getElementsByTagName(XMLTags.QUERGVPLINKS).item(0).getTextContent());
		}
		double querGleisLinks = 0;
		if (node.getElementsByTagName(XMLTags.QUERLINKESGLEIS).getLength() ==1) {			
			querGleisLinks = Double.valueOf(node.getElementsByTagName(XMLTags.QUERLINKESGLEIS).item(0).getTextContent());
		}
		double querGleisRechts = 0;
		if (node.getElementsByTagName(XMLTags.QUERRECHTESGLEIS).getLength() ==1) {			
			querGleisRechts = Double.valueOf(node.getElementsByTagName(XMLTags.QUERRECHTESGLEIS).item(0).getTextContent());
		}
		double gleisabstand = 0;
		if (node.getElementsByTagName(XMLTags.GLEISABSTAND).getLength() ==1) {
			gleisabstand = Double.valueOf(node.getElementsByTagName(XMLTags.GLEISABSTAND).item(0).getTextContent());
		}
		
		LageskizzenGVPDAO dao = new LageskizzenGVPDAO(punktNrGVPLinks,  stationGVPLinks, hoehenmaßGVPLinks, querGVPLinks, punktNrGVPRechts, 
				stationGVPRechts,  hoehenmaßGVPRechts, querGleisLinks,  querGleisRechts, gleisabstand);
		return dao;
	}
	
	private LageskizzenWeichenDAO getLageskizzenWeicheFromNode(Element node){
		double stationWeiche = Double.valueOf(node.getElementsByTagName(XMLTags.STATIONWEICHE).item(0).getTextContent());
		String nummerWeiche = "";
		if (node.getElementsByTagName(XMLTags.WEICHENNR).getLength() ==1) {
			nummerWeiche = node.getElementsByTagName(XMLTags.WEICHENNR).item(0).getTextContent();
		}
		String bezWeiche = node.getElementsByTagName(XMLTags.WEICHENBEZ).item(0).getTextContent();
		
		LageskizzenWeichenDAO dao = new LageskizzenWeichenDAO(stationWeiche, nummerWeiche, bezWeiche);
		return dao;
	}
	
	public void loadLageskizze(){
		lageskizzenNode = (Element) doc.getElementsByTagName(XMLTags.LAGESKIZZE).item(0);
		
		//GVPs laden
		NodeList gvpNodes = lageskizzenNode.getElementsByTagName(XMLTags.GVP);
		LageskizzenGVPDAO gvpDAO;
		for(int i = 0; i < gvpNodes.getLength(); i++){
			gvpDAO = getLageskizzenGVPFromNode((Element) gvpNodes.item(i));
			lageskizzenGVPs.add(gvpDAO);
			
		}
		
		//Weichen laden
		NodeList weichenNodes = lageskizzenNode.getElementsByTagName(XMLTags.WEICHE);
		LageskizzenWeichenDAO weichenDAO;
		for(int i = 0; i < weichenNodes.getLength(); i++){
			weichenDAO = getLageskizzenWeicheFromNode((Element) weichenNodes.item(i));
			lageskizzenWeichen.add(weichenDAO);
		}
		
		
	}
	
	public SortedSet<LageskizzenGVPDAO> getLageskizzenGVPs(){
		return lageskizzenGVPs;
	}
	
	public SortedSet<LageskizzenWeichenDAO> getLageskizzenWeichen(){
		return lageskizzenWeichen;
	}
	
	private Element createLageskizzenGVPNode(LageskizzenGVPDAO dao){
		//Knoten für eine LageskizzenGVP anlegen
		Element gvp = doc.createElement(XMLTags.GVP);
		
		//Knoten für Punktnummer GVP links anlegen
		if (!dao.getpunktNrGVPLinks().equals("")) {
			Element punktNrGVPLinks = doc.createElement(XMLTags.PUNKTNUMMERGVPLINKS);
			punktNrGVPLinks.appendChild(doc.createTextNode(dao.getpunktNrGVPLinks()));
			gvp.appendChild(punktNrGVPLinks);
		}
		//Knoten für Station GVP links anlegen
		if (dao.getstationGVPLinks() != 0) {
			Element stationGVPLinks = doc.createElement(XMLTags.STATIONLINKS);
			stationGVPLinks.appendChild(doc.createTextNode(String.valueOf(dao.getstationGVPLinks())));
			gvp.appendChild(stationGVPLinks);		
		}
		//Knoten für Höhenmaß GVP links anlegen
		if (dao.gethoehenmaßGVPLinks() != 0) {
			Element hoehenmaßGVPLinks = doc.createElement(XMLTags.HOEHENMASSLINKS);
			hoehenmaßGVPLinks.appendChild(doc.createTextNode(String.valueOf(dao.gethoehenmaßGVPLinks())));
			gvp.appendChild(hoehenmaßGVPLinks);
		}
		//Knoten für Punktnummer GVP rechts anlegen
		if (!dao.getpunktNrGVPRechts().equals("")) {
			Element punktNrGVPRechts = doc.createElement(XMLTags.PUNKTNUMMERGVPRECHTS);
			punktNrGVPRechts.appendChild(doc.createTextNode(dao.getpunktNrGVPRechts()));
			gvp.appendChild(punktNrGVPRechts);
		}
		//Knoten für Station GVP rechts anlegen
		if (dao.getstationGVPRechts() != 0) {
			Element stationGVPRechts = doc.createElement(XMLTags.STATIONRECHTS);
			stationGVPRechts.appendChild(doc.createTextNode(String.valueOf(dao.getstationGVPRechts())));
			gvp.appendChild(stationGVPRechts);
		}
		//Knoten für Höhenmaß GVP rechts anlegen
		if (dao.gethoehenmaßGVPRechts() != 0) {
			Element hoehenmaßGVPRechts = doc.createElement(XMLTags.HOEHENMASSRECHTS);
			hoehenmaßGVPRechts.appendChild(doc.createTextNode(String.valueOf(dao.gethoehenmaßGVPRechts())));
			gvp.appendChild(hoehenmaßGVPRechts);		
		}
		//Knoten für Quer GVP links anlegen
		if (dao.getquerGVPLinks() != 0) {
			Element querGVPLinks = doc.createElement(XMLTags.QUERGVPLINKS);
			querGVPLinks.appendChild(doc.createTextNode(String.valueOf(dao.getquerGVPLinks())));
			gvp.appendChild(querGVPLinks);		
		}
		//Knoten für Quermaß linkes Gleis
		if (dao.getquerGleisLinks() != 0) {
			Element querGleisLinks = doc.createElement(XMLTags.QUERLINKESGLEIS);
			querGleisLinks.appendChild(doc.createTextNode(String.valueOf(dao.getquerGleisLinks())));
			gvp.appendChild(querGleisLinks);
		}
		//Knoten für Quermaß rechtes Gleis
		if (dao.getquerGleisRechts() != 0) {
			Element querGleisRechts = doc.createElement(XMLTags.QUERRECHTESGLEIS);
			querGleisRechts.appendChild(doc.createTextNode(String.valueOf(dao.getquerGleisRechts())));
			gvp.appendChild(querGleisRechts);
		}
		//Knoten für Gleisabstand
		if (dao.getgleisabstand() != 0) {
			Element gleisabstand = doc.createElement(XMLTags.GLEISABSTAND);
			gleisabstand.appendChild(doc.createTextNode(String.valueOf(dao.getgleisabstand())));
			gvp.appendChild(gleisabstand);
		}
		
		return gvp;
	}
	
	private Element createLageskizzenWeichenNode(LageskizzenWeichenDAO dao){
		//Knoten für eine LageskizzenWeiche anlegen
		Element weiche = doc.createElement(XMLTags.WEICHE);
		
		//Knoten für Station Weiche anlegen
		Element stationWeiche = doc.createElement(XMLTags.STATIONWEICHE);
		stationWeiche.appendChild(doc.createTextNode(String.valueOf(dao.getstationWeiche())));
		weiche.appendChild(stationWeiche);
		//Knoten für Weichennummer anlegen
		 if (!dao.getnummerWeiche().equals("")) {
		    Element nummerWeiche = doc.createElement(XMLTags.WEICHENNR);
			nummerWeiche.appendChild(doc.createTextNode(dao.getnummerWeiche()));
			weiche.appendChild(nummerWeiche);			
		 }
		//Knoten für Weichenbezeichnung anlegen
		Element bezWeiche = doc.createElement(XMLTags.WEICHENBEZ);
		bezWeiche.appendChild(doc.createTextNode(dao.getbezWeiche()));
		weiche.appendChild(bezWeiche);
		
		return weiche;
	}
	
	private BauwerkslinienDAO getBauwerkslinienElementFromNode(Element node) {

		String bauwerk = node.getElementsByTagName(XMLTags.BAUWERK).item(0).getTextContent();
		double stationierung = Double.valueOf(node.getElementsByTagName(XMLTags.STATIONIERUNG).item(0).getTextContent());
	
		double endstationierung = stationierung;
		if (node.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).getLength() == 1) {
			endstationierung = Double.valueOf(node.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).item(0).getTextContent());
		}		
		
		double hoehe = 0;
		if (node.getElementsByTagName(XMLTags.HOEHE).getLength() == 1) {
			hoehe = Double.valueOf(node.getElementsByTagName(XMLTags.HOEHE).item(0).getTextContent());
		}
		
		String besonderheiten = "";
		if (node.getElementsByTagName(XMLTags.BESONDERHEITEN).getLength() == 1) {
			besonderheiten = node.getElementsByTagName(XMLTags.BESONDERHEITEN).item(0).getTextContent();
		}

		BauwerkslinienDAO dao = new BauwerkslinienDAO(bauwerk, stationierung, endstationierung,	hoehe, besonderheiten);

		return dao;
	}
	
	private void loadBauwerkslinie(){
		bauwerkslinienNode = (Element) doc.getElementsByTagName(XMLTags.BAUWERKSLINIE).item(0);
		
		NodeList bauwerkslinienNodes = bauwerkslinienNode.getElementsByTagName(XMLTags.BAUWERKSLINIEN_ELEMENT);
		BauwerkslinienDAO dao;
		for(int i = 0; i < bauwerkslinienNodes.getLength(); i++){
			dao = getBauwerkslinienElementFromNode((Element) bauwerkslinienNodes.item(i));
			bauwerkslinienElemente.add(dao);
		}
	}
	
	public SortedSet<BauwerkslinienDAO> getBauwerkslinienElemente(){
		return bauwerkslinienElemente;
	}
	
	private Element createBauwerkslinienElementNode(BauwerkslinienDAO dao){
		//Knoten für eine Bauwerkslinie anlegen
		Element bauwerkslinienElementNode = doc.createElement(XMLTags.BAUWERKSLINIEN_ELEMENT);
		
		//Knoten für Bauwerk anlegen
		Element bauwerk = doc.createElement(XMLTags.BAUWERK);
		bauwerk.appendChild(doc.createTextNode(dao.getBauwerk()));
		bauwerkslinienElementNode.appendChild(bauwerk);
		//Knoten für Stationierung anlegen
		Element stationierung = doc.createElement(XMLTags.STATIONIERUNG);
		stationierung.appendChild(doc.createTextNode(String.valueOf(dao.getStationierungVonInMeter())));
		bauwerkslinienElementNode.appendChild(stationierung);
		//Knoten für Endstationierung anlegen
		if (dao.getStationierungBisInMeter() != dao.getStationierungVonInMeter()) {
			Element endstationierung = doc.createElement(XMLTags.ENDSTATIONIERUNG);
			endstationierung.appendChild(doc.createTextNode(String.valueOf(dao.getStationierungBisInMeter())));
			bauwerkslinienElementNode.appendChild(endstationierung);
		}		
		//Knoten für Hoehe anlegen
		if (dao.getHoeheInMeter() != 0) {
			Element hoehe = doc.createElement(XMLTags.HOEHE);
			hoehe.appendChild(doc.createTextNode(String.valueOf(dao.getHoeheInMeter())));
			bauwerkslinienElementNode.appendChild(hoehe);
		}
		//Knoten für Besonderheiten anlegen
		if (!dao.getBesonderheiten().equals("")) {
			Element besonderheiten = doc.createElement(XMLTags.BESONDERHEITEN);
			besonderheiten.appendChild(doc.createTextNode(dao.getBesonderheiten()));
			bauwerkslinienElementNode.appendChild(besonderheiten);
		}
		
		return bauwerkslinienElementNode;
	}
	
	private Element createProjektNode(ProjektDatenDAO dao){
		Element projektNode = doc.createElement("Projekt");

		//Knoten für AuftragsNummer erstellen
		Element auftragsNrNode = doc.createElement("Auftragsnummer");
		auftragsNrNode.appendChild(doc.createTextNode(dao.getAuftragsNr()));
		projektNode.appendChild(auftragsNrNode);
		//Knoten für Projektbeschreibung erstellen
		Element projektBeschreibungsNode = doc.createElement("Projektbeschreibung");
		projektBeschreibungsNode.appendChild(doc.createTextNode(dao.getProjektBeschreibung()));
		projektNode.appendChild(projektBeschreibungsNode);
		//Knoten für Anzahl der Gleise erstellen
		Element gleisAnzahlNode = doc.createElement("Gleisanzahl");
		gleisAnzahlNode.appendChild(doc.createTextNode(String.valueOf(dao.getGleisAnzahl())));
		projektNode.appendChild(gleisAnzahlNode);
		//Knoten für Anzahl der Gleise erstellen
		Element geschwindigkeitNode = doc.createElement("Entwurfsgeschwindigkeit");
		geschwindigkeitNode.appendChild(doc.createTextNode(String.valueOf(dao.getGeschwindigkeit())));
		projektNode.appendChild(geschwindigkeitNode);
		//Knoten für Koordinatensystem erstellen
		if (!dao.getKoordinatensystem().equals("")) {
			Element koordinatensystemNode = doc.createElement("Koordinatensystem");
			koordinatensystemNode.appendChild(doc.createTextNode(dao.getKoordinatensystem()));
			projektNode.appendChild(koordinatensystemNode);
		}
		//Knoten für Hoehensystem erstellen
		if (!dao.getHoehensystem().equals("")) {
			Element hoehensystemNode = doc.createElement("Hoehensystem");
			hoehensystemNode.appendChild(doc.createTextNode(dao.getHoehensystem()));
			projektNode.appendChild(hoehensystemNode);
		}
		
		//Knoten für GleisElemente erstellen
		gleisNode = doc.createElement("Gleise");
		for(GleisDAO gleisElement : gleisElemente){
			gleisNode.appendChild(createGleisElementNode(gleisElement));
		}
		projektNode.appendChild(gleisNode);
		
		//Knoten für BauwerkslinienElemente erstellen
		bauwerkslinienNode = doc.createElement("Bauwerkslinie");
		for(BauwerkslinienDAO bauwerkslinienElement : bauwerkslinienElemente){
			bauwerkslinienNode.appendChild(createBauwerkslinienElementNode(bauwerkslinienElement));
		}
		projektNode.appendChild(bauwerkslinienNode);
		
		//Knoten für LageskizzenElemente erstellen
		lageskizzenNode = doc.createElement("Lageskizze");
		Element gvpsNode = doc.createElement("GVPs");
		lageskizzenNode.appendChild(gvpsNode);
		for(LageskizzenGVPDAO gvp : lageskizzenGVPs){
			gvpsNode.appendChild(createLageskizzenGVPNode(gvp));
		}
		Element weichenNode = doc.createElement("Weichen");
		lageskizzenNode.appendChild(weichenNode);
		for(LageskizzenWeichenDAO weiche : lageskizzenWeichen){
			weichenNode.appendChild(createLageskizzenWeichenNode(weiche));
		}
		projektNode.appendChild(lageskizzenNode);
		
		return projektNode;
	}
	
	private Document buildDocument(){
		DocumentBuilder builder = null;
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			builder = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		doc = builder.newDocument();
		doc.appendChild(createProjektNode(projekt));
		
		return doc;
	}
	
	public void loadGleise() {
		gleisNode = (Element) projektNode.getElementsByTagName("Gleise").item(0);
		
		NodeList gleisNodes = gleisNode.getElementsByTagName("Gleis");
		Element gleis;
		GleisDAO dao;
		for(int i = 0; i < gleisNodes.getLength(); i++){
			gleis = (Element) gleisNodes.item(i);
			
			int gleisID = Integer.valueOf(gleis.getAttribute("id"));
			String bezeichnung = ((Element)gleis.getElementsByTagName("Bezeichnung").item(0)).getTextContent();
			double anfangsStation = Double.valueOf(((Element)gleis.getElementsByTagName("Anfangsstation").item(0)).getTextContent());
			double abstandKmLinie = 0;
			if(gleis.getElementsByTagName("Abstand_km-Linie").getLength() == 1){
				abstandKmLinie = Double.valueOf(gleis.getElementsByTagName("Abstand_km-Linie").item(0).getTextContent());
			}
			 
			
			Element kruemmungslinienNode = (Element) gleis.getElementsByTagName("Krümmungslinie").item(0);
			SortedSet<KruemmungslinienDAO> kruemmungslinienElemente = loadKruemmungslinienElemente(kruemmungslinienNode);
			
			Element ueberhoehungslinienNode = (Element) gleis.getElementsByTagName("Überhöhungslinie").item(0);
			SortedSet<UeberhoehungslinienDAO> ueberheohungslinienElemente = loadUeberhoehungslinienElemente(ueberhoehungslinienNode);
			
			Element hoehenlinienNode = (Element) gleis.getElementsByTagName("Höhenlinie").item(0);
			SortedSet<HoehenlinienDAO> hoehenlinienElemente = loadHoehenlinienElemente(hoehenlinienNode);
	
			dao = new GleisDAO(gleisID, bezeichnung, anfangsStation, abstandKmLinie, kruemmungslinienElemente, ueberheohungslinienElemente, hoehenlinienElemente);
			
			gleisElemente.add(dao);
		}
	}
	
	private Element createGleisElementNode(GleisDAO dao){
		//Knoten für ein GleisElement anlegen
		Element gleisElement = doc.createElement("Gleis");
		
		//Attribut für ID anlegen
		Attr id = doc.createAttribute("id");
		id.setValue(String.valueOf(dao.getGleisID()));
		gleisElement.setAttributeNode(id);
		//Knoten für Bezeichnung anlegen
		Element bezeichnung = doc.createElement("Bezeichnung");
		bezeichnung.appendChild(doc.createTextNode(String.valueOf(dao.getBezeichnung())));
		gleisElement.appendChild(bezeichnung);
		//Knoten für Anfangsstation anlegen
		Element anfangsStation = doc.createElement("Anfangsstation");
		anfangsStation.appendChild(doc.createTextNode(String.valueOf(dao.getAnfangsStation())));
		gleisElement.appendChild(anfangsStation);
		//Knoten für Abstand_km-Linie anlegen		
		Element abstandKmLinie = doc.createElement("Abstand_km-Linie");
		abstandKmLinie.appendChild(doc.createTextNode(String.valueOf(dao.getAbstandKmLinie())));
		gleisElement.appendChild(abstandKmLinie);
		
		//Höhenlinie hinzufügen
		Element hoehenlinie = doc.createElement("Höhenlinie");
		for(HoehenlinienDAO hoehenlinienElement : dao.getHoehenlinienElemente()){
			hoehenlinie.appendChild(createHoehenlinienElementNode(hoehenlinienElement));
		}
		gleisElement.appendChild(hoehenlinie);
		
		//Krümmungslinie hinzufügen
		Element kruemmungslinie = doc.createElement("Krümmungslinie");
		for(KruemmungslinienDAO kruemmungslinienElement : dao.getKruemmungslinienElemente()){
			kruemmungslinie.appendChild(createKruemmungslinienElementNode(kruemmungslinienElement));
		}
		gleisElement.appendChild(kruemmungslinie);
		
		//Überhöhungslinie hinzufügen
		Element ueberhoehungslinie = doc.createElement("Überhöhungslinie");
		for(UeberhoehungslinienDAO ueberhoehungslinienElement : dao.getUeberhoehungslinienElemente()){
			ueberhoehungslinie.appendChild(createUeberhoehunglinienElementNode(ueberhoehungslinienElement));
		}
		gleisElement.appendChild(ueberhoehungslinie);
		
		return gleisElement;
	}
	
	public List<GleisDAO> getGleisElemente(){
		return gleisElemente;
	}
	
	private void printNodes(NodeList nodeList){
		for(int i = 0; i < nodeList.getLength(); i++){
			System.out.println(nodeList.item(i));
		}
	}
	
	public void setProjekt(ProjektDatenDAO projekt){
		this.projekt = projekt;
	}
	
	public void setCurrentGleis(GleisDAO currentGleis){
		this.currentGleis = currentGleis;
	}
	
	public GleisDAO getCurrentGleis(){
		return currentGleis;
	}
	
	public ProjektDatenDAO getProjekt(){
		return projekt;
	}
	
	public static void main(String[] args) {
		Manager.getInstance().loadExistingProjekt("test");
	}
}
